﻿using UnityEngine;
using System.Collections;
using SongeNS;
using System.IO;
using LitJson;
using System.Collections.Generic;
using System;
using Jhqc.EditorCommon;


//ID 对应 SceneNode JsonData 字典

/// <summary>组件库管理</summary>
public class CompLib
{
    public const string EventConfigLoaded = "EventConfigLoaded";
    public const string PrefabDefaultWall = "defaultWall";

    static CompLib instance;
    public static CompLib Instance
    {
        get
        {
            if (instance == null)
                instance = new CompLib();
            return instance;
        }
    }


    static GameObject brokenPrefab;
    public static GameObject BrokenPrefab
    {
        get
        {
            if (brokenPrefab == null)
            {
                brokenPrefab = GameObject.CreatePrimitive(PrimitiveType.Cube);
            }
            return brokenPrefab;
        }
    }

    /// <summary>组件原件的父级gameObject</summary>
    GameObject compPrefabFolder;
    /// <summary>按CompCode缓存的组件原件</summary>
    Dictionary<string, GameObject> compPrefabDic;


    public CompLib()
    {
        compPrefabFolder = new GameObject();
        compPrefabFolder.name = "compPrefabFolder";
        compPrefabDic = new Dictionary<string, GameObject>();
    }

    public JsonData ConfigJD;

    /// <summary>组件类别-组件名字典</summary>
    public Dictionary<string, List<string>> ClassCompDic;

    /// <summary>组件-组件数据字典</summary>
    public Dictionary<string, CompIconVO> CompDataDic;

    Dictionary<string, List<CompIconVO>> ClassIconDic;

    /// <summary>从本地读取组件库配置(备用)</summary>
    public void LoadConfig()
    {
        string url = Application.streamingAssetsPath + "/compLibConfig.txt";
        ConfigJD = JsonUtils.ReadJsonFile(url);
        ClassCompDic = new Dictionary<string, List<string>>();
        CompDataDic = new Dictionary<string, CompIconVO>();

        for (int iClass = 0, lenClass = ConfigJD.Count; iClass < lenClass; iClass++)
        {
            JsonData classJD = ConfigJD[iClass];
            string className = classJD.ReadString("type");
            JsonData dataJD = classJD.ReadJsonData("data");
            for (int iComp = 0, lenComp = dataJD.Count; iComp < lenComp; iComp++)
            {
                JsonData compJD = dataJD[iComp];
                string compName = compJD.ReadString("code");
                if (compName == null)
                    Debug.Log(compName + "" + compJD.ToJson());
                CompDataDic.AddRep(compName, new CompIconVO(compJD));
                ClassCompDic.AddToList(className, compName);
            }
        }

        ClassIconDic = new Dictionary<string, List<CompIconVO>>();
        foreach (var className in ClassCompDic.Keys)
        {
            List<string> nameList = ClassCompDic[className];
            for (int iName = 0, nName = nameList.Count; iName < nName; iName++)
            {
                CompIconVO icon;
                if (CompDataDic.TryGetValue(nameList[iName], out icon))
                {
                    ClassIconDic.AddToList(className, icon);
                }
            }
        }

        onConfigLoaded();
    }

    /// <summary>
    /// 从服务器读取组件库配置信息
    /// </summary>
    public void LoadCompConfigFromNet(List<JsonData> _pCompList)
    {
        List<JsonData> m_pCompList = _pCompList;
        ClassCompDic = new Dictionary<string, List<string>>();
        CompDataDic = new Dictionary<string, CompIconVO>();

        for (int iClass = 0; iClass < m_pCompList.Count; iClass++)
        {
            JsonData classJD = m_pCompList[iClass];
            string className = classJD.ReadString("tag");
            JsonData dataJD = classJD.ReadJsonData("data");
            string strCompCode = classJD.ReadString("code");

            CompDataDic.AddRep(strCompCode, new CompIconVO(classJD));
            ClassCompDic.AddToList(className, strCompCode);
        }

        ClassIconDic = new Dictionary<string, List<CompIconVO>>();
        foreach (var className in ClassCompDic.Keys)
        {
            List<string> nameList = ClassCompDic[className];
            for (int iName = 0, nName = nameList.Count; iName < nName; iName++)
            {
                CompIconVO icon;
                if (CompDataDic.TryGetValue(nameList[iName], out icon))
                {
                    ClassIconDic.AddToList(className, icon);
                }
            }
        }

        onConfigLoaded();
    }

    public bool IsConfigLoaded = false;

    void onConfigLoaded()
    {
        IsConfigLoaded = true;
        EventManager.instance.DispatchEvent(null, EventConfigLoaded);
        if (onGetLib != null)
            onGetLib(ClassIconDic);
    }

    Dictionary<string, List<Action<GameObject>>> loadCallbackDic = new Dictionary<string, List<Action<GameObject>>>();
    Dictionary<string, List<Action<HttpResp.ErrorType, string>>> loadFailCallbackDic = new Dictionary<string, List<Action<HttpResp.ErrorType, string>>>();

    public void GetPrefab(string compCode, Action<GameObject> callback, Action<HttpResp.ErrorType, string> failCallback)
    {
        if (compCode == PrefabDefaultWall)
        {
            callback((GameObject)Resources.Load("SongyiTest/WallCreate/TestWall"));
        }
        else
        {
            GameObject prefab;
            if (compCode == null)
            {
                failCallback(HttpResp.ErrorType.LogicError, "compCode参数不能为null!");
                return;
            }
            if (compPrefabDic.TryGetValue(compCode, out prefab))
            {
                callback(prefab);
                return;
            }
            else
            {
                if (!CompDataDic.ContainsKey(compCode))
                    callback(null);
                else
                {
                    if(loadCallbackDic.ContainsKey(compCode))
                    {
                        loadCallbackDic.AddToList(compCode, callback);
                        loadFailCallbackDic.AddToList(compCode, failCallback);

                    }
                    else
                    {
                        loadCallbackDic.AddToList(compCode, callback);
                        loadFailCallbackDic.AddToList(compCode, failCallback);

                        CompIconVO ci = CompDataDic[compCode];
                        if ((ci == null || ci.dataJD == null))
                        {
                            failCallback(HttpResp.ErrorType.LogicError, "CompIconVO==null 或者 CompIconVO的JsonData=null");
                            return;
                        }

                        prefab = new GameObject();
                        prefab.name = "prefab_"+ compCode;
                        int childNum = ci.dataJD.Count;
                        TaskManager tm = new TaskManager();

                        for (int iJD = 0, lenJD = ci.dataJD.Count; iJD < lenJD; iJD++)
                        {
                            JsonData jd = ci.dataJD[iJD];

                            if (!jd.Keys.Contains("guid"))
                            {
                                string compT = jd.ReadString("t");
                                GetPrefab(compT, partComp =>
                                {
                                    Debug.Log("请修改该组件的配置信息为简单组件: "+compCode);
                                    if (partComp != null)
                                    {
                                        GameObject child = GameObject.Instantiate(partComp);
                                        child.SetActive(true);
                                        child.transform.parent = prefab.transform;
                                        child.transform.localPosition = jd.ReadVec3("p");
                                        child.transform.localEulerAngles = jd.ReadVec3("e");
                                        child.transform.localScale = jd.ReadVec3("s");

                                        childNum--;
                                        if (childNum == 0)
                                        {
                                            prefab.transform.parent = compPrefabFolder.transform;
                                            prefab.SetActive(false);
                                            compPrefabDic.AddRep(compCode, prefab);
                                            if (loadCallbackDic.ContainsKey(compCode) && loadCallbackDic[compCode] != null)
                                            {
                                                for (int iCallback = 0, nCallback = loadCallbackDic[compCode].Count; iCallback < nCallback; iCallback++)
                                                {
                                                    loadCallbackDic[compCode][iCallback](prefab);
                                                }
                                                loadCallbackDic.Remove(compCode);
                                            }
                                            //callback(prefab);
                                        }
                                    }

                                }, (errorType, errorInfo) =>
                                {
                                    if (loadFailCallbackDic.ContainsKey(compCode) && loadFailCallbackDic[compCode] != null)
                                    {
                                        for (int iCallback = 0, nCallback = loadFailCallbackDic[compCode].Count; iCallback < nCallback; iCallback++)
                                        {
                                            loadFailCallbackDic[compCode][iCallback](errorType, errorInfo);
                                        }
                                        loadFailCallbackDic.Remove(compCode);
                                    }


                                    return;
                                });
                            }
                            else
                            {
                                SceneNode nodecp = new SceneNode(jd);

                                loadModel(nodecp, 3, result =>
                                {
                                    //修改FBXLoader后组件无法加载
                                    GameObject child;
                                    bool isAssetBundle = nodecp.fileName.EndsWith(".assetbundle");
                                    if (isAssetBundle)
                                    {
                                        LoadingResult lr = result;
                                        var ab = LoadAssetBundle(result.rNode.GetResource());
                                        GameObject model = ab.LoadAsset<GameObject>(ab.GetAllAssetNames()[0]);
                                        ab.Unload(false);
                                        child = GameObject.Instantiate(model);
                                    }
                                    else
                                    {
                                        if (Jhqc.UnityFbxLoader.FbxLoader.LoadFbx(result.rNode.GetResource(), out child)
                                            != Jhqc.UnityFbxLoader.ErrorCode.LoadOk)
                                        {

                                        }
                                        else
                                        {
                                            MonoHelper.Instance.AddDefaultMat(child);
                                        }
                                    }


                                    string filename = result.rNode.GetName();
                                    if (filename.Length > 4)
                                        child.name = filename.Substring(0, filename.Length - 4);
                                    child.transform.localPosition = StringUtil.StringToVector3(nodecp.postion);
                                    child.transform.localRotation = StringUtil.StringToQuaternion(nodecp.rotation);
                                    if(nodecp.scale != null)
                                        child.transform.localScale = StringUtil.StringToVector3(nodecp.scale);

                                    SongeUtil.forAllChildren(child, tar =>
                                    {
                                        if (tar.GetComponent<MeshFilter>() != null)
                                        {
                                            if (tar.GetComponent<Collider>() != null)
                                                UnityEngine.Object.Destroy(tar.GetComponent<Collider>());
                                            tar.AddComponent<MeshCollider>();
                                        }
                                    });
                                    // 解析过程材质 需要赋值完毕后才算模型原件创建完成
                                    if (!isAssetBundle)
                                    {

                                        SceneChildNode.SetNodeMaterial(child, nodecp, () => { 
                                        //nodecp.SetMaterial(child, ()=> {


                                            child.transform.parent = prefab.transform;
                                            childNum--;
                                            if (childNum == 0)
                                            {
                                                prefab.transform.parent = compPrefabFolder.transform;
                                                prefab.SetActive(false);
                                                object test1 = compPrefabDic;
                                                object test2 = loadCallbackDic;
                                                compPrefabDic.AddRep(compCode, prefab);


                                                if (loadCallbackDic.ContainsKey(compCode) && loadCallbackDic[compCode] != null)
                                                {
                                                    for (int iCallback = 0, nCallback = loadCallbackDic[compCode].Count; iCallback < nCallback; iCallback++)
                                                    {

                                                        Action<GameObject> ca = loadCallbackDic[compCode][iCallback];
                                                        GameObject ta = prefab;
                                                        MonoHelper.Instance.StartCoroutine(delay(ca, ta));
                                                        //loadCallbackDic[compCode][iCallback](prefab);

                                                    }
                                                    loadCallbackDic.Remove(compCode);
                                                }
                                                //callback(prefab);
                                            }


                                        });
                                    }
                                    else
                                    {
                                        //NOTE 重复代码...
                                        child.transform.parent = prefab.transform;
                                        childNum--;
                                        if (childNum == 0)
                                        {
                                            prefab.transform.parent = compPrefabFolder.transform;
                                            prefab.SetActive(false);
                                            object test1 = compPrefabDic;
                                            object test2 = loadCallbackDic;
                                            compPrefabDic.AddRep(compCode, prefab);


                                            if (loadCallbackDic.ContainsKey(compCode) && loadCallbackDic[compCode] != null)
                                            {
                                                for (int iCallback = 0, nCallback = loadCallbackDic[compCode].Count; iCallback < nCallback; iCallback++)
                                                {

                                                    Action<GameObject> ca = loadCallbackDic[compCode][iCallback];
                                                    GameObject ta = prefab;
                                                    MonoHelper.Instance.StartCoroutine(delay(ca, ta));

                                                }
                                                loadCallbackDic.Remove(compCode);
                                            }
                                        }
                                    }

                                }, (errorType, errorInfo) =>
                                {
                                    if (loadFailCallbackDic.ContainsKey(compCode) && loadFailCallbackDic[compCode] != null)
                                    {
                                        for (int iCallback = 0, nCallback = loadFailCallbackDic[compCode].Count; iCallback < nCallback; iCallback++)
                                        {
                                            loadFailCallbackDic[compCode][iCallback](errorType, errorInfo);
                                        }
                                        loadFailCallbackDic.Remove(compCode);
                                    }
                                    return;
                                });
                            }
                        }
                    }
                }
            }
        }
    }

    IEnumerator delay(Action<GameObject> ca, GameObject ta)
    {
        //NOTE nodecp.SetMaterial(child);方法会等待多次EndOfFrame
        for (int i = 0; i < 10; i++)
            yield return new WaitForEndOfFrame();
        ca(ta);
    }


    //三次重试机制
    void loadModel(SceneNode nodecp, int retry, Action<LoadingResult> callback, Action<HttpResp.ErrorType, string> failCallback)
    {
        LoadManagerTest.Instance.Load(onLoaded => {
            ResourceManager.Instance.LoadHttpResource(nodecp.fileName, nodecp.fileCrc, result =>
            {
                callback(result);
                onLoaded();
            }, (errorType, errorInfo) =>
            {
                if (retry > 0)
                {
                    loadModel(nodecp, retry - 1, callback, failCallback);
                    onLoaded();
                }
                else
                {
                    failCallback(errorType, errorInfo);
                    onLoaded();
                }
            }, UICONST.PriorityForDownloadComp);
        });
    }


    Action<Dictionary<string, List<CompIconVO>>> onGetLib;

    public void GetCompLib(Action<Dictionary<string, List<CompIconVO>>> onGet)
    {
        if (IsConfigLoaded)
            onGet(ClassIconDic);
        else
            onGetLib += onGet;
    }

    public float getDefaultWalllength(string compCode)
    {
        CompIconVO icon;
        if (CompDataDic.TryGetValue(compCode, out icon))
        {
            return icon.WallLength;
        }
        else
            return 3f;
    }


    #region 加载外网ab文件 byte格式

    Dictionary<byte[], AssetBundle> abDic = new Dictionary<byte[], AssetBundle>();

    public AssetBundle LoadAssetBundle(byte[] tarByteArr)
    {
        AssetBundle newAB = AssetBundle.LoadFromMemory(tarByteArr);
        return newAB;
    }

    #endregion

}

public class CompIconVO
{
    /// <summary>图标显示名称</summary>
    public string CompName;
    /// <summary>图标图片地址</summary>
    public string CompIconUrl;
    public string m_strImgName;
    public string m_strImgCrc;
    public string CompCode;
    public float WallLength;
    public JsonData dataJD;

    public CompIconVO(JsonData jd)
    {
        CompName = jd.ReadString("name");
        CompIconUrl = jd.ReadString("url");
        m_strImgCrc = jd.ReadString("picCrc");
        m_strImgName = jd.ReadString("picName");
        CompCode = jd.ReadString("code");
        WallLength = jd.ReadFloat("wallLength", 3f);
        dataJD = jd.ReadJsonData("data");
    }

}


